<script lang="ts" setup>
import { FullscreenOutlined } from '@ant-design/icons-vue'
import { nextTick, onMounted, onUnmounted, ref, toRaw, toRefs } from 'vue'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
import * as monaco from 'monaco-editor'
import { launchIntoFullscreen } from '@/utils/util.ts'

const props = withDefaults(defineProps<propType>(), {
  modelValue: '',
  language: 'json',
  height: '100px',
})
const emit = defineEmits(['update:modelValue'])

interface propType {
  modelValue: string
  language?: string
  height?: string
}

const { modelValue } = toRefs(props)
const editorContainer = ref<HTMLElement>()

window.MonacoEnvironment = {
  getWorker(_: any, label: string) {
    if (label === 'json')
      return new jsonWorker()

    if (label === 'css' || label === 'scss' || label === 'less')
      return new cssWorker()

    if (label === 'html' || label === 'handlebars' || label === 'razor')
      return new htmlWorker()

    if (label === 'typescript' || label === 'javascript')
      return new tsWorker()

    return new editorWorker()
  },
}

const editor = ref<monaco.editor.IStandaloneCodeEditor>()
const intervalId = ref<any>()
onMounted(() => {
  nextTick(() => {
    // 初始化monaco编辑器
    const theme = isDark.value ? 'vs-dark' : 'vs-light'
    editor.value = monaco.editor.create(editorContainer.value!, {
      theme,
      value: modelValue.value,
      language: props.language,
      automaticLayout: true,
      lineNumbers: 'on',
      minimap: {
        enabled: false,
      },
      insertSpaces: true,
      tabSize: 2,
    })
    // 实时更新内容方式一
    toRaw(editor.value).onDidChangeModelContent(() => {
      const dynamicContent = toRaw(editor.value)?.getValue()
      emit('update:modelValue', dynamicContent)
    })
  })
})

onUnmounted(() => {
  // 销毁monaco编辑器
  if (intervalId.value)
    clearInterval(intervalId.value)

  if (editor.value) {
    const instance = toRaw(editor.value)
    instance.dispose()
  }
})

// 画布全屏
function fullscreen() {
  const container = document.getElementById('monaco-container')
  launchIntoFullscreen(container)
}

const dark = useDark()

// 监听isDark的变化
watch(isDark, () => {
  // 更新monaco编辑器主题
  if (isDark.value) {
    document.querySelector('.editor-container')!.classList.add('border-dark')
    monaco.editor.setTheme('vs-dark')
  }
  else {
    document.querySelector('.editor-container')!.classList.remove('border-dark')
    monaco.editor.setTheme('vs-light')
  }
})
</script>

<template>
  <div class="editor-container" :class="dark ? 'border-dark' : ''">
    <div class="full-btn" @click="fullscreen">
      <FullscreenOutlined />
    </div>
    <div id="monaco-container" ref="editorContainer" :style="{ height: props.height }" />
  </div>
</template>

<style scoped>
/* 添加样式 */
.editor-container {
  padding: 3px;
  border-style: solid;
  border-color: #d9d9d9;
  border-width: 1px;
  border-radius: 6px;
  transition: all 0.2s;
}
.editor-container:hover {
  border-color: #4096ff;
}
.editor-container:focus-within {
  border-color: #4096ff;
  box-shadow: 0 0 0 2px rgba(5, 145, 255, 0.1);
  border-inline-end-width: 1px;
  outline: 0;
}
.border-dark {
  border-color: #424242;
}
.full-btn {
  display: none;
  opacity: 0;
  z-index: 10;
  position: absolute;
  top: 5px;
  right: 30px;
  font-size: 18px;
  cursor: pointer;
  padding: 5px;
}
.editor-container:hover .full-btn {
  display: block;
  opacity: 1;
}
</style>
